package com.example.backetballgame.gui;

import com.example.backetballgame.event.EventBus;
import com.example.backetballgame.event.FrameEvent;
import com.example.backetballgame.player.Player;
import com.example.backetballgame.store.StoreManage;
import com.example.backetballgame.team.Team;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

/**
 * The main class that represents the BattleFrame, which is the GUI of the game.
 */

public class BattleFrame extends JFrame {

    private static List<String> infos = new ArrayList<>();

    {
        infos.add("Your player exerted too much force and made a mistake.");
        infos.add("Your player has outstanding skills and scored successfully.");
        infos.add("Your player defended poorly and the opponent scored.");
        infos.add("Your player grabbed the rebound and won an offensive opportunity for the team.");
        infos.add("Your player is too tired and needs to rest.");
        infos.add("Your player fouled, giving the opponent a chance to take a free throw.");
        infos.add("Your player jumped too early and was easily faked out by the opponent.");
        infos.add("Your player is full of energy and completed a beautiful fast break score.");
        infos.add("Your player made a passing mistake and the opponent scored easily.");
        infos.add("Your player defended well and successfully stole the ball from the opponent.");
    }

    private JPanel topPanel, leftPanel, rightPanel, centerPanel, bottomPanel;
    private JLabel gameTitle, gameTime, scoreLabel, myTeamNameLabel, enemyTeamNameLabel;
    private JTextArea myTeamInfoArea, gameProcessArea, enemyTeamInfoArea, eventArea;

    private JButton startButton, pauseButton, endButton, saveButton;

    private int maxTime = 3 * 60;
    private int currentTime = maxTime;
    private boolean started;
    private boolean paused;
    private JScrollPane gameScrollPane;
    private int userScore;
    private int systemScore;
    private boolean ended;

    /**
     * Constructor of BattleFrame, initializes all the components and sets up the GUI.
     */
    public BattleFrame() {
        // 设置窗口标题

        // 初始化各个组件
        initTopPanel();
        initLeftPanel();
        initRightPanel();
        initCenterPanel();
        initBottomPanel();

        background();


        topPanel.setBackground(new Color(255, 255, 255, 128));
        leftPanel.setOpaque(false);
        centerPanel.setOpaque(false);
        bottomPanel.setOpaque(false);
        // 将各个面板添加到窗口中
        add(topPanel, BorderLayout.NORTH);
        add(leftPanel, BorderLayout.WEST);
        add(rightPanel, BorderLayout.EAST);
        add(centerPanel, BorderLayout.CENTER);
        add(bottomPanel, BorderLayout.SOUTH);

        // 设置窗口大小和位置
        setSize(800, 600);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    /**
     * Initializes the bottom panel of the GUI.
     */
    private void initTopPanel() {
        topPanel = new JPanel(new BorderLayout());

        // 初始化标题栏
        gameTitle = new JLabel("Summit Battle");
        gameTitle.setFont(new Font("Arial", Font.BOLD, 26));
        gameTitle.setHorizontalAlignment(JLabel.CENTER);

        // 初始化比分栏
        scoreLabel = new JLabel(String.format("%s %d : %d %s", StoreManage.getTeamName(), userScore, systemScore, StoreManage.getOpponentTeam().getTeamName()));
        scoreLabel.setFont(new Font("Arial", Font.PLAIN, 24));
        scoreLabel.setHorizontalAlignment(JLabel.CENTER);

        // 初始化时间栏
        gameTime = new JLabel("00:00");
        gameTime.setFont(new Font("Arial", Font.PLAIN, 16));
        gameTime.setHorizontalAlignment(JLabel.RIGHT);

        // 将标题栏、比分栏和时间栏添加到顶部面板中
        topPanel.add(gameTitle, BorderLayout.CENTER);
        topPanel.add(scoreLabel, BorderLayout.SOUTH);
        topPanel.add(gameTime, BorderLayout.EAST);
    }

    /**
     * Sets up the background image for the frame.
     */
    private void background() {
        // 创建背景图片
        // 创建一个标签，并将背景图片设置为标签的图标
        JLabel label = new JLabel();

        label.setIcon(new ImageIcon(getClass().getClassLoader().getResource("background.jpg")));
        // 设置标签的大小和位置
        label.setBounds(0, 0, 800, 520);
        ((JPanel) this.getContentPane()).setOpaque(false);
        this.getLayeredPane().add(label, new Integer(Integer.MIN_VALUE));

    }


    /**
     * Initializes the left panel of the GUI.
     */
    private void initLeftPanel() {
        leftPanel = new JPanel(new BorderLayout());
        leftPanel.setOpaque(false);

        // 初始化球队信息模块
        myTeamInfoArea = new JTextArea(20, 20);
        myTeamInfoArea.setEditable(false);
        myTeamInfoArea.setFont(new Font("Arial", Font.PLAIN, 16));

        myTeamInfoArea.setBackground(new Color(255, 255, 128, 128));
//        myTeamInfoArea.setSelectedTextColor(new Color(255,255,128,128));


        // 添加球员信息到左侧面板中
        leftPanel.add(myTeamInfoArea, BorderLayout.CENTER);

        // 填充球员信息
        fillPlayerInfo(myTeamInfoArea, StoreManage.getActivePlayers());
    }

    /**
     * Initializes the right panel of the GUI.
     */
    private void initRightPanel() {
        rightPanel = new JPanel(new BorderLayout());

        // 初始化球队信息模块
        enemyTeamInfoArea = new JTextArea(20, 20);
        enemyTeamInfoArea.setEditable(false);
        enemyTeamInfoArea.setFont(new Font("Arial", Font.PLAIN, 16));


        // 添加球员信息到右侧面板中
        rightPanel.add(enemyTeamInfoArea, BorderLayout.CENTER);
        rightPanel.setOpaque(false);
        enemyTeamInfoArea.setBackground(new Color(255, 255, 128, 128));

        List<Player> systemPlayers = StoreManage.getOpponentTeam().getPlayerList();
        // 填充球员信息
        fillPlayerInfo(enemyTeamInfoArea, systemPlayers);
    }

    /**
     * Initializes the center panel of the GUI.
     */
    private void initCenterPanel() {
        centerPanel = new JPanel(new BorderLayout());

        // 初始化比赛进程模块
        gameProcessArea = new JTextArea(3, 40);
//        gameProcessArea.setEditable(false);
        gameProcessArea.setFont(new Font("Arial", Font.PLAIN, 16));
        gameProcessArea.setText("");
        gameProcessArea.setBackground(new Color(255, 255, 255, 128));
        gameScrollPane = new JScrollPane(gameProcessArea);

        gameScrollPane.setOpaque(false);

        // 初始化突发事件提示
        eventArea = new JTextArea(3, 40);
        eventArea.setEditable(false);
        eventArea.setFont(new Font("Arial", Font.BOLD, 16));
        eventArea.setForeground(Color.RED);
        eventArea.setText("--------------------");
        JScrollPane eventScrollPane = new JScrollPane(eventArea);
        eventScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

        // 将比赛进程模块和突发事件提示添加到中间面板中
        centerPanel.add(gameScrollPane, BorderLayout.CENTER);
        centerPanel.add(eventScrollPane, BorderLayout.SOUTH);
        centerPanel.setOpaque(false);
    }

    /**
     * Initializes the bottom panel of the GUI.
     */
    private void initBottomPanel() {
        bottomPanel = new JPanel(new FlowLayout());

        // 初始化操作按钮模块
        startButton = new JButton("Start Game");
        startButton.addActionListener(event -> {
            startGame();
        });
        pauseButton = new JButton("Pause Game");
        pauseButton.addActionListener(event -> {
            pauseGame();
        });
        endButton = new JButton("End Game");
        endButton.addActionListener(event -> {
            endGame();
        });
        saveButton = new JButton("Save Score");
        saveButton.addActionListener(event -> {
            if ((!started && !paused) || ended) {
                dispose();
                EventBus.getInstance().publish(new FrameEvent(1));
            }
        });

        // 将操作按钮添加到底部面板中
        bottomPanel.add(startButton);
        bottomPanel.add(pauseButton);
        bottomPanel.add(endButton);
        bottomPanel.add(saveButton);
    }

    private void pauseGame() {
        if (started) {
            started = false;
            paused = true;
        }
    }

    private void endGame() {
        if (started && !ended) {
            ended = true;

            startButton.setEnabled(false);
            pauseButton.setEnabled(false);
            endButton.setEnabled(false);
        }
    }

    private static final int MAX_SCORE_PER_MINUTE = 4; // 最大得分
    private static final int MAX_FATIGUE_INCREMENT = 10; // 劳累度增长值

    private void startGame() {
        if ((!started || paused) && !ended) {
            if (!paused) {
                appendBattleInfo("The game has started!");
            }
            started = true;
            paused = false;
            new Thread(() -> {
                int sleep = 0;
                int battleInterval = ThreadLocalRandom.current().nextInt(3, 8);
                while (started && currentTime > 0) {
                    try {
                        Thread.sleep(!ended ? 1000L : 5L);
                    } catch (InterruptedException ignored) {
                    }
                    sleep++;

                    if (sleep >= battleInterval) {
                        battle();

                        battleInterval = ThreadLocalRandom.current().nextInt(3, 8);
                        sleep = 0;
                    }

                    currentTime = Math.max(0, currentTime - 1);

                    gameTime.setText(formatSecondsToTime(ended ? 0 : currentTime));
                }

                if (currentTime == 0) {
                    ended = true;
                    appendBattleInfo("Game over! The final score is " + userScore + ":" + systemScore + "!");
                    if (userScore > systemScore) {
// Issue rewards
                        Team team = StoreManage.getOpponentTeam();
                        StoreManage.saveTotalMonty(StoreManage.getTotalMonty() + team.getGoldReward());
                        StoreManage.savePoints(StoreManage.getPoints() + team.getPoints());

                        appendBattleInfo(String.format("Congratulations on winning this game, earning points: %s, money: %s", team.getPoints(), team.getGoldReward()));
                    } else {
                        appendBattleInfo("Your team lost in this game, please keep trying!");
                    }
                }
            }).start();
        }
    }

    private void battle() {
        List<Player> userPlayers = StoreManage.getActivePlayers();
        List<Player> systemPlayers = StoreManage.getOpponentTeam().getPlayerList();

        Player userPlayer = getRandomPlayer(userPlayers);
        Player systemPlayer = getRandomPlayer(systemPlayers);

        appendBattleInfo(String.format("<%s> is battling against <%s>...", userPlayer.getName(), systemPlayer.getName()));

        //对抗
        double leftAbility = userPlayer.calculateOverallAbility();
        double rightAbility = systemPlayer.calculateOverallAbility();
        int score = generateRandomScore();
        boolean win = leftAbility == rightAbility ? ThreadLocalRandom.current().nextBoolean() : leftAbility > rightAbility;

        int randomIndex = ThreadLocalRandom.current().nextInt(infos.size());

        if (win) {
            userScore += score;
            int index = randomIndex % 2 != 0 ? randomIndex : Math.abs(randomIndex - 1);
            appendBattleInfo(String.format("%s <%s> earned %s points.", infos.get(index), userPlayer.getName(), score));
        } else {
            systemScore += score;
            int index = randomIndex % 2 == 0 ? randomIndex : randomIndex - 1;
            appendBattleInfo(String.format("%s <%s> earned %s points.", infos.get(index), systemPlayer.getName(), score));
        }

        int fatigue = ThreadLocalRandom.current().nextInt(5, MAX_FATIGUE_INCREMENT);
        userPlayer.incrementFatigue(fatigue);
        systemPlayer.incrementFatigue(fatigue);

        fillPlayerInfo(myTeamInfoArea, StoreManage.getActivePlayers());
        fillPlayerInfo(enemyTeamInfoArea, StoreManage.getOpponentTeam().getPlayerList());

        scoreLabel.setText(String.format("%s %d : %d %s", StoreManage.getTeamName(), userScore, systemScore, StoreManage.getOpponentTeam().getTeamName()));
    }

    /**
     * append battle info
     * @param info
     */
    private void appendBattleInfo(String info) {
        gameProcessArea.append(info);
        gameProcessArea.append("\n");
        JScrollBar scrollBar = gameScrollPane.getVerticalScrollBar();
        scrollBar.setValue(scrollBar.getMaximum());
    }

    /**
     * get random player
     * @param players
     * @return
     */
    public Player getRandomPlayer(List<Player> players) {
        List<Player> activePlayer = players.stream().filter(it -> it.getFatigue() < 100).collect(Collectors.toList());
        if (activePlayer.isEmpty()) {
            return players.get(ThreadLocalRandom.current().nextInt(players.size()));
        } else {
            return activePlayer.get(ThreadLocalRandom.current().nextInt(activePlayer.size()));
        }
    }

    /**
     * generate random score
     * @return
     */
    public int generateRandomScore() {
        // 生成 1 到 MAX_SCORE_PER_MINUTE 之间的随机整数（包括边界值）
        return ThreadLocalRandom.current().nextInt(1, MAX_SCORE_PER_MINUTE + 1);
    }

    /**
     * format seconds to time
     * @param seconds
     * @return
     */
    public String formatSecondsToTime(int seconds) {
        int hours = seconds / 3600;
        int minutes = (seconds % 3600) / 60;
        int remainingSeconds = seconds % 60;

        String formattedTime = String.format("%02d:%02d:%02d", hours, minutes, remainingSeconds);
        return formattedTime;
    }

    /**
     * fill player info
     * @param area
     * @param players
     */
    private void fillPlayerInfo(JTextArea area, List<Player> players) {
        area.setText("");
        for (Player player : players) {
            area.append(player.getName() + ": \n");
            area.append(String.format("Strength: %-3s Defence: %-3s Fatigue: %-3s \n", player.getStrength(), player.getDefense(), player.getFatigue()));
        }
    }

    public static void main(String[] args) {
        // 启动游戏界面
        new BattleFrame();
    }
}